package com.supermap.dataservice.grid.griddata.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.supermap.dataservice.grid.GridTools;
import com.supermap.dataservice.grid.griddata.cache.LocalCache;
import com.supermap.dataservice.grid.griddata.dao.GridProductMapper;
import com.supermap.dataservice.grid.griddata.entity.GridData;
import com.supermap.dataservice.grid.griddata.entity.GridProduct;
import com.supermap.dataservice.mysql.config.DynamicDataSourceContextHolder;
import com.supermap.dataservice.util.DateUtil;
import com.supermap.dataservice.util.JSONUtils;
import com.supermap.dubbo.api.grid.GridService;
import com.supermap.dubbo.api.grid.entity.GridProductDo;
import net.bytebuddy.asm.Advice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.awt.geom.Point2D;
import java.util.List;
import java.util.Map;

/**
 * @Author:zhoujian
 * @Desciption:格点数据服务
 * @date:2019-04-25 14:50
 * @version:v1.0.0
 */
@Service
public class GridServiceImpl implements GridService{

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private GridProductMapper gridProductMapper;
    @Autowired
    private NetcdfServiceImpl netcdfServiceImpl;

    @Override
    public JSONUtils getGridValueByLonLat(String dataContent , String elementCode , String productDate, String areaCode , int validCode , List<Point2D> point2DList)
    {
       try{
           //查询数据库，获取要素记录
           //构建查询条件
           GridProduct queryProduct = new GridProduct();
           queryProduct.setDataContent(dataContent);
           queryProduct.setAreaCode(areaCode);
           queryProduct.setElementCode(elementCode);
           queryProduct.setProductDate(DateUtil.StringToDate(productDate,"yyyy-MM-dd"));
           queryProduct.setValidCode(validCode);
           GridProduct resultProduct = gridProductMapper.selectBySelective(queryProduct);
           if (resultProduct == null)
           {
               return  new JSONUtils().setMsg("查询数据为空");
           }
           //提取格点值返回
           Map<String,Float> pointGridValueMap = GridTools.getGridValueByLonLats(resultProduct.getNcUrl(),resultProduct.getElementCode(),point2DList);
           return  new JSONUtils().setData(pointGridValueMap).setCountSum(pointGridValueMap == null ? 0: pointGridValueMap.size());

       }catch (Exception ex)
       {
           logger.info("根据经纬度获取格点值异常,异常信息为：" +ex);
           return  new JSONUtils().setMsg("获取格点值异常");
       }

    }

    @Override
    public JSONUtils getGridValueByLonLat(Integer id , List<Point2D> point2DList)
    {
        try{
            synchronized (this){
               Object object = LocalCache.get(id);
               if (object != null){
                //获取缓存数据
                   logger.info("从本地缓存中获取数据");
                   GridTools.GridData gridData = (GridTools.GridData) object;
                   Map<String,Float> pointGridValueMap = GridTools.getGridValueByLonLats( gridData ,point2DList);
                   return  new JSONUtils().setData(pointGridValueMap).setCountSum(pointGridValueMap == null ? 0: pointGridValueMap.size());
               }else{
                   //从数据库中获取数据
                   DynamicDataSourceContextHolder.setDataSourceKey("ds1");
                   //查询数据库，获取要素记录
                   GridProduct resultProduct = gridProductMapper.selectByPrimarykey(id);
                   if (resultProduct == null)
                   {
                       return  new JSONUtils().setMsg("查询数据为空");
                   }
                   //提取格点值返回
                   GridTools.GridData gridData = GridTools.getGridData(resultProduct.getNcUrl(),resultProduct.getElementCode());
                   Map<String,Float> pointGridValueMap = GridTools.getGridValueByLonLats( gridData ,point2DList);
                   //数据放入缓存
                   LocalCache.put(id,gridData);
                   return  new JSONUtils().setData(pointGridValueMap).setCountSum(pointGridValueMap == null ? 0: pointGridValueMap.size());
               }
            }
        }catch (Exception ex)
        {
            logger.info("根据经纬度获取格点值异常,异常信息为：" + ex);
            return  new JSONUtils().setMsg("获取格点值异常");
        }
    }


    @Override
    public JSONUtils getSingeValidGrid(String forecastDate, int valid, String element, String areaCode) {
        try
        {
            //使用本地缓存
            String key = element + "." + forecastDate+"."+ valid+ "."+areaCode.substring(0, 2);
            Object object = null;
            synchronized (this)
            {
                object = LocalCache.get(key);
            }
            if (object != null)
            {
                logger.info(String.format("从缓存中获取到数据,key=%s", key));
                return  new JSONUtils().setData(object).setCountSum(1);
            }else {
                //使用双重判断缓存中取出的数据是否为空
                //存在情况是第一次判断缓存中取出的数据为空，于此同时有另一线程刚刚好向缓存中写入了一条数据，这个时候在取缓存一次就能够取到数据，避免从数据库中取数据
                synchronized (this)
                {
                    object = LocalCache.get(key);
                }
                if (object != null)
                {
                    logger.info(String.format("从缓存中获取到数据,key=%s", key));
                }
                //查询数据库
                GridProduct gridProduct = gridProductMapper.selectByDateAndElement(forecastDate, element, valid, areaCode);
                if (gridProduct == null)
                {
                    return new JSONUtils().setCountSum(0);
                }
                //获取netcdf文件路径
                //解析文件
                GridData gridData = netcdfServiceImpl.read(gridProduct);
                if (gridData != null)
                {
                    //将数据设置到缓存中
                    LocalCache.put(key , gridData);
                    return  new JSONUtils().setData(gridData).setCountSum(1);
                }else {

                    return  new JSONUtils().setMsg("未能解析到格点数据");
                }
            }

        } catch (Exception e)
        {
            logger.error("获取格点数据异常，异常信息:"+e.getMessage());
            return  null;
        }
    }
}